package com.pvdnc.riru;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
public class WriteDexFromOat {
    /**
     * 从内存中搜索数据，并返回在内存中的偏移
     ***/
    public static int findPos(MappedByteBuffer data, int offset, byte[] found) {
        for (int i = offset; i < data.capacity(); i++) {
            boolean bFound = true;
            for (int j = 0; j < found.length; j++) {
                bFound = bFound && data.get(i + j) == found[j];
            }
            if (bFound) {
                return i;
            }
        }
        return -1;
    }

    private static void write_to_file(MappedByteBuffer buffer, int offset, int dexsize, int file_count, String out)
            throws IOException {
        RandomAccessFile file = new RandomAccessFile(String.format("%s%02d.dex", out, file_count), "rw");
        FileChannel channel = file.getChannel();
        byte[] data = new byte[dexsize];
        buffer.position(offset);
        buffer.get(data);
        ByteBuffer bw = ByteBuffer.wrap(data);
        channel.write(bw);
        channel.close();
        file.close();
    }

    public static void oat2dex(String in, String out) throws IOException {
        RandomAccessFile raf = new RandomAccessFile(in, "rw");
        // 内存映射文件
        FileChannel channel = raf.getChannel();
        MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, raf.length());
        int file_count = 0;
        int length = (int) raf.length();
        //dex头
        byte[] magic = {0x64, 0x65, 0x78, 0x0A, 0x30, 0x33, 0x35, 0x00};

        int offset = 0;
        while (offset != -1) {
            offset = findPos(buffer, offset + 8, magic);

            if (offset == -1) { // 未发现dex magic
                break;
            }

            int dexsize = (buffer.get(offset + 35) << 24) | (buffer.get(offset + 34) & 0xff) << 16
                    | (buffer.get(offset + 33) & 0xff) << 8 | (buffer.get(offset + 32) & 0xff);

            if (offset + dexsize > length)
                continue;
            write_to_file(buffer, offset, dexsize, ++file_count, out);
        }
        channel.close();
        raf.close();
    }
}
